#ifndef __DRAM_APP_H__
#define __DRAM_APP_H__

#define   MAX_DRAM_SLOT_NUM   0x08
#define   DDR4_SPD_SIZE       0x200
#define   DDR5_SPD_SIZE       0x400

typedef struct {
  UINT8 DRAMPresent;
  UINT8 SPDData[DDR4_SPD_SIZE];
}DDR4_INFO;

typedef struct {
  UINT8 DRAMPresent;
  UINT8 SPDData[DDR5_SPD_SIZE];
}DDR5_INFO;


#define   PCI_BASE_ASSRESS   0xE0000000
#define   MAX_BUS_NUM        0x100
#define   MAX_DEV_NUM        0x20
#define   MAX_FUN_NUM        0x08

#define   PCI_IO_CF8         0xCF8
#define   PCI_IO_CFC         0xCFC

#define   USE_CF8_CFC        0x01

#define PCI_DEV_MMBASE(Bus, Device, Function) \
  ( \
    (UINTN)PCI_BASE_ASSRESS + (UINTN) (Bus << 20) + (UINTN) (Device << 15) + (UINTN)(Function << 12) \
  )

#define PCI_IO_CF8_ADDRESS(Bus, Device, Function) \
  ( \
    ((UINT32)(Bus << 16) | (UINT32)(Device << 11) | (UINT32)(Function << 8) | (0x80000000)) \
  )

#define PCI_REG_BASE(Bus, Device, Function, Reg) (PCI_DEV_MMBASE(Bus, Device, Function) + Reg)

#define   SMBUS_HOST_STATUS              0x00
#define   SMBUS_HOST_SLAVE_STATUS        0x01

#define   SMBUS_HOST_CTL                 0x02 // HOST Control Register, A read to this register will clear the pointer in the 32-byte buffer.
#define   SMBUS_HOST_CTL_BYTE            0x04
#define   SMBUS_HOST_CTL_BYTE_DATA       0x08
#define   SMBUS_HOST_CTL_WORD_DATA       0x0C
#define   SMBUS_HOST_CTL_PROC_CALL       0x10
#define   SMBUS_HOST_CTL_BLOCK           0x14
#define   SMBUS_HOST_CTL_I2C_READ        0x18
#define   SMBUS_HOST_CTL_BLOCK_PROC      0x1C
#define   SMBUS_HOST_CTL_CMD_START       BIT6

#define   SMBUS_HOST_CMD                 0x03
#define   SMBUS_HOST_ADR                 0x04
#define   SMBUS_HOST_DATA_0              0x05
#define   SMBUS_HOST_STA_CLEAR           0xDE

#define   DDR5_SPD_FALG                  0x51
#define   DDR5_MR11                      0x0B

#define   RETRY_COUNT                    0x03

EFI_STATUS
ReadByteBySmbus (
  IN   UINT8  SlaveAddress,
  IN   UINT8  Command,
  IN   UINT8  Offset,
  OUT  UINT8  *Vaule
  );

EFI_STATUS
WriteByteBySmbus (
  IN   UINT8  SlaveAddress,
  IN   UINT8  Command,
  IN   UINT8  Offset,
  IN   UINT8  Vaule
  );

EFI_STATUS
GetSmbusIOPortByMmio (
  OUT UINT16 *IoPort
  );

EFI_STATUS
GetSmbusIoPortByIO(
  OUT UINT16  *IoPort
  );

BOOLEAN
IsSPD5 ();

EFI_STATUS
ReadSPD4Info ();

VOID
PrintSPD4Info ();

EFI_STATUS
ReadSPD5Info ();

VOID
PrintSPD5Info ();

VOID
GetDRAMCapacity (
  IN UINT8  DensityAndBanks,
  IN UINT8  PackageType,
  IN UINT8  ModuleOrganization,
  IN UINT8  ModuleBusWidth
  );

UINT16
GetDRAMSpeed (
  IN UINT8 TimeBases,
  IN INT8 MinCycleTime,
  IN INT8 FindMinCycleTime
  );

UINT16
GetCL(
  IN UINT8 *DataBuffer,
  IN UINT8 TimeBasesIndex,
  IN UINT8 MinCycleTimeIndex,
  IN UINT8 FindMinCycleTimeIndex,
  IN UINT8 MCASLatencyTimeIndex,
  IN UINT8 FindMinCASLatencyTimeIndex
  );

UINT16
CalculateDdr4DimmChecksum (
  IN UINT8 *DataBuffer
  );

#endif